package au.edu.qut.bpm.genbinder.genetic.evaluation.costmodels;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Set;

import au.edu.qut.bpm.genbinder.GeneticBinder;
import au.edu.qut.bpm.genbinder.genetic.evaluation.LogEvaluator;
import au.edu.qut.bpm.genbinder.models.Activity;
import au.edu.qut.bpm.genbinder.models.ConcreteEventLog;

public class MultiObjectiveCostModel extends LogEvaluator {
	// This is just a simple cost model to illustrate the prototype;
	private final static double TIMEUNIT = 1;
	//private final static double TIMEUNIT = (1000 * 60) // when discrete = false
	private final static long HORIZON = 60;
	private final static long HORIZONSTART = 0;
	private final static CostCalculations costCalc = new CostCalculations();
	public static double caseCost = 0.00;
	public static double actCost = 0.00;
	public static double resCost = 0.00;
	public double costPerViolation = 0;
	//public static double avgResUtil = 0.00;
	
	//private final static double COSTPERTIMEUNIT = 30;
	//private final static double COSTPERRESOURCE = 50;
	//private final static double COSTPERUTILIZATION = 10;
	//private final static long HORIZON = (long) (TIMEUNIT * 2);
	
	//private static double nrTimesExecuted = 0;//tightening

	public MultiObjectiveCostModel(double costPerViolation) {
		this.costPerViolation = costPerViolation;
		// TODO Auto-generated constructor stub
	}

	public double getFitness(ConcreteEventLog candidate, List<? extends ConcreteEventLog> population) {
		//System.out.println("Start Calculation = " + new Date().toString());
		double violationCost = 0.00, logCost = 0.00;
		//costPerViolation = 1700;
		
		double[] coefs = new double[] { costPerViolation, costPerViolation, costPerViolation, costPerViolation, 1 };
		// 0: Overlap
		// 1: Misorder
		// 2: Resourceclash
		// 3: Invalidresource
		/* Tightening CM
		nrTimesExecuted++;
		double max = 1000;
		double w = nrTimesExecuted / (double) GeneticBinder.POPULATION_SIZE;
		if (w > max)
			w = max;

		double[] coefs = new double[] {
				30 + w / max * 1000,
				30 + w / max * 1000,
				30 + w / max * 1000,
				30 + w / max * 1000,
				1 };
		//*/
		List<Set<Activity>> v = candidate.getLogViolatingActivities();
		
		violationCost = coefs[0] * (double) v.get(0).size()
				+ coefs[1] * (double) v.get(1).size()
				+ coefs[2] * (double) v.get(2).size()
				+ coefs[3] * (double) v.get(3).size();
		
		logCost = coefs[4] * getCost(candidate);
		double totalViolation = 0.00;
		totalViolation = v.get(0).size() + v.get(1).size() + v.get(2).size() + v.get(3).size();
		String safe = "Unsafe";
		
		if (totalViolation == 0.0)
			safe = "Safe";
		
		String s = String.format("%.5f", caseCost) + " " + String.format("%.5f", actCost) + " " + String.format("%.5f", resCost) + " " + 
					String.format("%.5f", logCost) + " " + String.format("%.5f", violationCost) + " " + String.format("%.5f", (logCost + violationCost)) + " " + 
					v.get(0).size() + " " + v.get(1).size() + " " + v.get(2).size() + " " + v.get(3).size() + " " + totalViolation + " " + safe;

//		System.out.println(s);
		
		try
		{
		    String filename= "logs/CostData" + GeneticBinder.strFileNameExtension + ".txt";
		    FileWriter fw = new FileWriter(filename,true); //the true will append the new data
		    fw.write(s + System.getProperty("line.separator"));//appends the string to the file
		    fw.close();
		}
		catch(IOException ioe)
		{
		    System.err.println("IOException: " + ioe.getMessage());
		}
		
		return violationCost + logCost;
	}

	@Override
	public double getCost(ConcreteEventLog candidate) {
		
		if (GeneticBinder.strLogType.equalsIgnoreCase("normal")) {
			//System.out.println("normal CM!");
			return costCalc.calculateCost(candidate, TIMEUNIT, HORIZON, HORIZONSTART);	//Cost Model for Normal Log
		} else if (GeneticBinder.strLogType.equalsIgnoreCase("doublecase")) {
			//System.out.println("DC CM!");
			return costCalc.calculateCostForDoubleCase(candidate, TIMEUNIT, HORIZON, HORIZONSTART);	//Cost Model for Double Cases Log
		} else if (GeneticBinder.strLogType.equalsIgnoreCase("doubletask")) {
			//System.out.println("DT CM!");
			return costCalc.calculateCostForDoubleTask(candidate, TIMEUNIT, HORIZON, HORIZONSTART);	//Cost Model for Double Tasks Log
		} else {
			return costCalc.calculateCost(candidate, TIMEUNIT, HORIZON, HORIZONSTART);	//Cost Model for Normal Log
		}
	}
}
